#include "grflib_stdafx.h"
#include "../include/TextureFormat.h"

namespace grflib
{
	namespace engine
	{
		namespace core
		{
			namespace texture_format
			{
				DXGI_FORMAT Mapping(const w32lib::ImagePtr &imgPtr)
				{
					if (0 == imgPtr.Get())
						return DXGI_FORMAT_UNKNOWN;

					UINT bpp = imgPtr.GetBPP();
					UINT channel = 0;
					w32lib::ImageBytePerChannel bpc = imgPtr.GetPixelFormat();

					if (w32lib::BPC_U8 == bpc)
					{
						channel = bpp / 8;
						if (1 == channel) return DXGI_FORMAT_R8_UNORM;
						else if (2 == channel) return DXGI_FORMAT_R8G8_UNORM;
						else if (3 == channel) return DXGI_FORMAT_UNKNOWN;
						else if (4 == channel) return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
					}
					else if (w32lib::BPC_U16 == bpc)
					{
						channel = bpp / 16;
						if (1 == channel) return DXGI_FORMAT_R16_UNORM;
						else if (2 == channel) return DXGI_FORMAT_R16G16_UNORM;
						else if (3 == channel) return DXGI_FORMAT_UNKNOWN;
						else if (4 == channel) return DXGI_FORMAT_R16G16B16A16_UNORM;
					}
					else if (w32lib::BPC_U32 == bpc)
					{
						channel = bpp / 32;
						if (1 == channel) return DXGI_FORMAT_R32_UINT;
						else if (2 == channel) return DXGI_FORMAT_R32G32_UINT;
						else if (3 == channel) return DXGI_FORMAT_R32G32B32_UINT;
						else if (4 == channel) return DXGI_FORMAT_R32G32B32A32_UINT;
					}
					else if (w32lib::BPC_F32 == bpc)
					{
						channel = bpp / 32;
						if (1 == channel) return DXGI_FORMAT_R32_FLOAT;
						else if (2 == channel) return DXGI_FORMAT_R32G32_FLOAT;
						else if (3 == channel) return DXGI_FORMAT_R32G32B32_FLOAT;
						else if (4 == channel) return DXGI_FORMAT_R32G32B32A32_FLOAT;
					}
					else if (w32lib::BPC_F64 == bpc)
					{
						return DXGI_FORMAT_UNKNOWN;
					}

					return DXGI_FORMAT_UNKNOWN;
				}

				bool Mapping(DXGI_FORMAT format,  UINT &bpc, UINT &channel, bool &isFloat)
				{
					bpc = 0;
					channel = 0;
					bool result = true;
					isFloat = false;

					//determine bpc
					switch (format)
					{
					case DXGI_FORMAT_R8_UNORM:
					case DXGI_FORMAT_R8G8_UNORM:
					case DXGI_FORMAT_R8G8B8A8_UNORM:
					case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
					case DXGI_FORMAT_B8G8R8A8_UNORM:
					case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
						bpc = 8;
						break;
					case DXGI_FORMAT_R16_UNORM:
					case DXGI_FORMAT_R16G16_UNORM:
					case DXGI_FORMAT_R16G16B16A16_UNORM:
						bpc = 16;
						break;
					case DXGI_FORMAT_R32_UINT:
					case DXGI_FORMAT_R32G32_UINT:
					case DXGI_FORMAT_R32G32B32A32_UINT:
						bpc = 32;
						break;
					case DXGI_FORMAT_R32_FLOAT:
					case DXGI_FORMAT_R32G32_FLOAT:
					case DXGI_FORMAT_R32G32B32_FLOAT:
					case DXGI_FORMAT_R32G32B32A32_FLOAT:
						bpc = 32;
						isFloat = true;
						break;
					default:
						result = false;
						break;
					}

					//determine channel
					switch (format)
					{
					case DXGI_FORMAT_R8_UNORM:
					case DXGI_FORMAT_R16_UNORM:
					case DXGI_FORMAT_R32_UINT:
					case DXGI_FORMAT_R32_FLOAT:
						channel = 1;
						break;
					case DXGI_FORMAT_R8G8_UNORM:
					case DXGI_FORMAT_R16G16_UNORM:
					case DXGI_FORMAT_R32G32_UINT:
					case DXGI_FORMAT_R32G32_FLOAT:
						channel = 2;
						break;
					case DXGI_FORMAT_R8G8B8A8_UNORM:
					case DXGI_FORMAT_B8G8R8A8_UNORM:
					case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
					case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
					case DXGI_FORMAT_R16G16B16A16_UNORM:
					case DXGI_FORMAT_R32G32B32A32_UINT:
					case DXGI_FORMAT_R32G32B32A32_FLOAT:
						channel = 4;
						break;
					default:
						result = false;
						break;
					}

					return result;
				}

				bool Mapping(D3D10_USAGE &d3dusage /*out*/, UINT &bindFlag /*out*/, UINT &cpuAccessFlag /*out*/, TextureSpec::TextureUsage usage, TextureSpec::BindTarget target)
				{
					using namespace TextureSpec;
					bindFlag = 0;
					cpuAccessFlag = 0;
					
					if (TU_CPU_READ & usage) //cpu can only read from staging resource
					{
						d3dusage = D3D10_USAGE_STAGING;
						cpuAccessFlag |= D3D10_CPU_ACCESS_READ;
					}
					else if (!(TU_CPU_READ & usage) && !(TU_CPU_WRITE & usage)) //cpu has no access
					{
						d3dusage = D3D10_USAGE_DEFAULT;
						if (TU_GPU_READ & usage)
							bindFlag |= D3D10_BIND_SHADER_RESOURCE;
						if (TU_GPU_WRITE & usage)
						{
							if (TextureSpec::BT_RGBA == target)
								bindFlag |= D3D10_BIND_RENDER_TARGET;
							else if (TextureSpec::BT_DEPTHSTENCIL == target)
								bindFlag |= D3D10_BIND_DEPTH_STENCIL;
						}
					}
					else if ((TU_GPU_READ | TU_CPU_WRITE) == usage)
					{
						d3dusage = D3D10_USAGE_DYNAMIC;
						bindFlag |= D3D10_BIND_SHADER_RESOURCE;
						cpuAccessFlag |= D3D10_CPU_ACCESS_WRITE;
					}

					return true;
				}

			} //namespace vertex_format
		} //namespace core
	} //namespace engine
} //namespace grflib